﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;

namespace RTF2XML
{
    class StyleControl : Control
    {
        #region Private Variables
        /// <summary>
        /// Parsed control text maching the list
        /// </summary>
        private string sControl = "";

        /// <summary>
        /// Input control text
        /// </summary>
        private string sControlText = "";

        /// <summary>
        /// Number following a numbered control
        /// </summary>
        private int iNumberedControlNum = -1;
        #endregion

        #region Lists of Controls
        public static new List<string> lstControls = new List<string>()
        {
            "tsrowd", "additive", "sautoupd", "shidden", "slocked", "spersonal", "scompose", "sreply", "keycode", "alt", "shift", "ctrl", "sqformat"
        };

        public static new List<string> lstNumberedControls = new List<string>()
        {
            "sbasedon", "snext", "slink", "styrsid", "ssemihidden", "fn", "spriority", "sunhideused", "s", "cs", "ds", "ts"
        };

        public static new List<string> lstDestinationControls = new List<string>()
        {
            "s", "cs", "ds", "ts"
        };
        #endregion

        /// <summary>
        /// Creates a new style control with the given control text
        /// </summary>
        /// <param name="controlText"></param>
        public StyleControl(string controlText)
        {
            //Uncomment below line if you want to keep the input text (for debugging)
            //this.sControlText = controlText;

            //Note that this logic is slightly different from the other controls.
            //This allows for a destination control to be a plain control or a numbered control as well as a destination control.
            //A special situation for the "s", "cs", "ds", and "ts" controls which are numbered controls, but should be treated as destination controls.
            if (lstDestinationControls.Where(c => controlText.StartsWith(c)).ToList().Count() == 1)
            {
                //Get the destination control
                string control = lstDestinationControls.Where(c => controlText.StartsWith(c)).ToList()[0];

                //Check to see if the number can be parsed out of it.
                string number = controlText.Replace(control, "");
                int n = -1;
                if (int.TryParse(number, out n))
                {
                    //If the number can be parsed out of it then it's a valid control
                    this.sControl = control;
                    this.iNumberedControlNum = n;
                    base.bDestination = true;
                }
            }

            //Check to see if the control is a regular control
            if (lstControls.Contains(controlText))
            {
                this.sControl = controlText;
            }
            //If it's not a regular control then check to see if it's a numbered control
            else
            {
                foreach (string control in lstNumberedControls)
                {
                    //If the input text starts with the numbered control
                    if (controlText.StartsWith(control))
                    {
                        //Try to parse the number out of the input text
                        string number = controlText.Replace(control, "");
                        int n = -1;
                        if (int.TryParse(number, out n))
                        {
                            //If the number can be parsed out then it's a valid control
                            this.sControl = control;
                            this.iNumberedControlNum = n;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Checks to see if the input control is part of the control class
        /// </summary>
        /// <param name="sControl">control to check</param>
        /// <returns>true if control is in style control class, false otherwise</returns>
        public static bool IsPartOfControl(string sControl)
        {
            //If it's a regular control or a destination control
            if (lstControls.Contains(sControl) || lstDestinationControls.Contains(sControl))
            {
                return true;
            }

            //Check to see if it's a numbered control
            foreach (string control in lstNumberedControls)
            {
                if (sControl.StartsWith(control))
                {
                    //Check to see if the number can be parsed out of the control
                    string number = sControl.Replace(control, "");
                    int n = 0;
                    if (int.TryParse(number, out n))
                    {
                        return true;
                    }
                }
            }

            return false;
        }

        /// <summary>
        /// Adds the control to the xml parent node in sequence with the other nodes
        /// </summary>
        /// <param name="xmlParentNode"></param>
        public override void AddXML(ref XmlElement xmlParentNode)
        {
            int iSeqNum = 0;

            if (xmlParentNode.HasChildNodes)
            {
                //Get the last sequence number of the other children nodes
                string seqNum = xmlParentNode.LastChild.Attributes["seq"].Value;
                if (int.TryParse(seqNum, out iSeqNum))
                {
                    //Increment the sequence number
                    iSeqNum++;
                }
                else
                {
                    throw new Exception("Sequence number is not valid");
                }
            }

            //Add a new element for the control
            XmlElement child = xmlParentNode.OwnerDocument.CreateElement(this.sControl);
            //Add the sequence number
            child.SetAttribute("seq", iSeqNum.ToString());
            //If the control is a numbered control
            if (this.iNumberedControlNum != -1)
            {
                //Add the number as an attribute
                child.SetAttribute("number", this.iNumberedControlNum.ToString());
            }
            //Add element to the parent node
            xmlParentNode.AppendChild(child);
        }
    }
}
